// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ui/events/gesture_detection/velocity_tracker_state.h"

#include "base/logging.h"
#include "ui/events/gesture_detection/motion_event.h"

namespace ui {
namespace {
    // Special constant to request the velocity of the active pointer.
    const int ACTIVE_POINTER_ID = -1;
}

VelocityTrackerState::VelocityTrackerState(VelocityTracker::Strategy strategy)
    : velocity_tracker_(strategy)
    , active_pointer_id_(ACTIVE_POINTER_ID)
{
}

VelocityTrackerState::~VelocityTrackerState() { }

void VelocityTrackerState::Clear()
{
    velocity_tracker_.Clear();
    active_pointer_id_ = ACTIVE_POINTER_ID;
    calculated_id_bits_.clear();
}

void VelocityTrackerState::AddMovement(const MotionEvent& event)
{
    velocity_tracker_.AddMovement(event);
}

void VelocityTrackerState::ComputeCurrentVelocity(int32_t units,
    float max_velocity)
{
    DCHECK_GE(max_velocity, 0);

    BitSet32 id_bits(velocity_tracker_.GetCurrentPointerIdBits());
    calculated_id_bits_ = id_bits;

    for (uint32_t index = 0; !id_bits.is_empty(); index++) {
        uint32_t id = id_bits.clear_first_marked_bit();

        float vx, vy;
        velocity_tracker_.GetVelocity(id, &vx, &vy);

        vx = vx * units / 1000.f;
        vy = vy * units / 1000.f;

        if (vx > max_velocity)
            vx = max_velocity;
        else if (vx < -max_velocity)
            vx = -max_velocity;

        if (vy > max_velocity)
            vy = max_velocity;
        else if (vy < -max_velocity)
            vy = -max_velocity;

        Velocity& velocity = calculated_velocity_[index];
        velocity.vx = vx;
        velocity.vy = vy;
    }
}

float VelocityTrackerState::GetXVelocity(int32_t id) const
{
    float vx;
    GetVelocity(id, &vx, NULL);
    return vx;
}

float VelocityTrackerState::GetYVelocity(int32_t id) const
{
    float vy;
    GetVelocity(id, NULL, &vy);
    return vy;
}

void VelocityTrackerState::GetVelocity(int32_t id,
    float* out_vx,
    float* out_vy) const
{
    DCHECK(out_vx || out_vy);
    if (id == ACTIVE_POINTER_ID)
        id = velocity_tracker_.GetActivePointerId();

    float vx, vy;
    if (id >= 0 && id <= MotionEvent::MAX_POINTER_ID && calculated_id_bits_.has_bit(id)) {
        uint32_t index = calculated_id_bits_.get_index_of_bit(id);
        const Velocity& velocity = calculated_velocity_[index];
        vx = velocity.vx;
        vy = velocity.vy;
    } else {
        vx = 0;
        vy = 0;
    }

    if (out_vx)
        *out_vx = vx;

    if (out_vy)
        *out_vy = vy;
}

} // namespace ui
